namespace ClassyBlog.DataAccess.Specs.Unit
{
    using System;

    using Machine.Specifications;
    using NSubstitute;

    using DomainObjects;

    [Subject(typeof(LazyPost))]
    public class when_creating_lazy_post_with_null_loader
    {
        private static Exception exception;

        Because of = () => exception =
            Catch.Exception(() => new LazyPost(null));

        It should_throw_exception = () =>
            exception.ShouldBeOfType<ArgumentNullException>();
    }

    public abstract class LazyPostSpec
    {
        protected static IArticleLoader<Post> loader;
        protected static LazyPost post;

        Establish context = () =>
        {
            loader = Substitute.For<IArticleLoader<Post>>();
            post = new LazyPost(loader);
        };
    }

    [Subject(typeof(LazyPost))]
    public class when_post_title_is_accessed_for_first_time : LazyPostSpec
    {
        Because of = () => { var title = post.Title; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_title_is_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.Title = "Welcome to first post of classy blog.";
            loader.ClearReceivedCalls();
        };

        Because of = () => { var title = post.Title; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_meta_keywords_is_accessed_for_first_time :
        LazyPostSpec
    {
        Because of = () => { var metakeywords = post.MetaKeywords; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_meta_keywords_is_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.MetaKeywords = "ASP.NET MVC, jQuery";
        };

        Because of = () =>
        {
            loader.ClearReceivedCalls();
            var metakeywords = post.MetaKeywords;
        };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_meta_description_is_accessed_for_first_time :
        LazyPostSpec
    {
        Because of = () => { var metadescription = post.MetaDescription; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_meta_description_is_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.MetaDescription = "This post summarize how to create an " +
                                   "modern single page application.";

            loader.ClearReceivedCalls();
        };

        Because of = () => { var metadescription = post.MetaDescription; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_author_is_accessed_for_first_time : LazyPostSpec
    {
        Because of = () => { var author = post.Author; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_author_is_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.Author = "Kazi Manzur Rashid";
            loader.ClearReceivedCalls();
        };

        Because of = () => { var author = post.Author; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_allow_comments_is_accessed_for_first_time :
        LazyPostSpec
    {
        Because of = () => { var allowComments = post.AllowComments; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_allow_comment_is_false : LazyPostSpec
    {
        Establish context = () =>
        {
            post.AllowComments = false;
            loader.ClearReceivedCalls();
        };

        Because of = () => { var allowComments = post.AllowComments; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_tags_are_accessed_for_first_time : LazyPostSpec
    {
        Because of = () => { var tags = post.Tags; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_tags_are_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.Tags.Add(new Tag { Title = "ASP.NET MVC" });
            loader.ClearReceivedCalls();
        };

        Because of = () => { var tags = post.Tags; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_body_is_accessed_for_first_time : LazyPostSpec
    {
        Because of = () => { var body = post.Body; };

        It should_lazy_load = () => loader.Received().Load(post);
    }

    [Subject(typeof(LazyPost))]
    public class when_post_body_is_set : LazyPostSpec
    {
        Establish context = () =>
        {
            post.Body = "This is the body of the first post.";
            loader.ClearReceivedCalls();
        };

        Because of = () => { var body = post.Body; };

        It should_not_lazy_load = () => loader.DidNotReceive().Load(post);
    }
}